﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ControlLibary
{
    public class TextColumn : DataGridViewColumn
    {
        public TextColumn() : base(new TextCell())
        {
            //CellTemplate = new TextCell();
            //ReadOnly = true;
        }

        public override DataGridViewCell CellTemplate
        {
            get
            {
                return base.CellTemplate;
            }
            set
            {
                if ((value != null) && !(value is TextCell))
                {
                    throw new InvalidCastException("Need System.Windows.Forms.TextCell");
                }
                base.CellTemplate = value;
            }
        }
    }

    public class TextCell : DataGridViewTextBoxCell
    {
        Dictionary<int, string> texts = null;

        Font font = null;

        Color highLightColor = Color.Blue;

        public Color HighLightColor
        {
            get { return highLightColor; }
            set { highLightColor = value; }
        }

        /// <summary>
        /// 当值更新的时候
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        protected override bool SetValue(int rowIndex, object value)
        {
            if (value != null)
            {
                texts = GetFormatValue(value.ToString());
                font = !this.HasStyle ? this.DataGridView.Font : (this.Style.Font == null ? this.DataGridView.Font : this.Style.Font);
            }
            return base.SetValue(rowIndex, value);
        }

        #region 绘制

        protected override void Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            if (value != null)
            {
                if (this.Selected == false)
                {
                    Rectangle rec = cellBounds;

                    Graphics g = graphics;

                    //First of all we draw the back ground.
                    using (SolidBrush brush = new SolidBrush(this.DataGridView.DefaultCellStyle.BackColor))
                    {
                        g.FillRectangle(brush, rec);
                    }

                    Rectangle rectBorder = new Rectangle(rec.Left - 1, rec.Top - 1, rec.Width, cellBounds.Height);

                    using (Pen p = new Pen(this.DataGridView.GridColor, 1.5f))
                    {
                        g.DrawRectangle(p, rectBorder);
                    }

                    //then draw the text
                    string text = value.ToString();

                    //首先计算要绘制的部分 

                    string str = string.Empty;

                    //int startIndex = text.Length;

                    bool flag = true;

                    //如何减少这里的循环次数  提高性能?
                    for (int i = 0; i < text.Length; i += 2)
                    {
                        str = text.Substring(0, text.Length - i);

                        SizeF sizeF = g.MeasureString(str, font, 2000, StringFormat.GenericTypographic);

                        if (sizeF.Width <= rec.Width - 10)
                        {
                            if (!flag)
                            {
                                var ss = text.Substring(0, text.Length - i + 1);

                                sizeF = g.MeasureString(str, font, 2000, StringFormat.GenericTypographic);

                                if (sizeF.Width <= rec.Width)
                                {
                                    str = ss;
                                }
                            }

                            break;
                        }

                        flag = false;
                    }

                    PointF pt = new PointF(rec.X, rec.Y + (rec.Height - font.Height) / 2);

                    using (SolidBrush brush_text = new SolidBrush(this.Selected ? Color.White : Color.Black))
                    {
                        using (SolidBrush brush_highLightText = new SolidBrush(highLightColor))
                        {
                            int StartIndex = 0;

                            int EndIndex = 0;

                            foreach (var dic in texts)
                            {
                                EndIndex = dic.Key;

                                if (EndIndex < str.Length)
                                {
                                    string draw = str.Substring(StartIndex, EndIndex - StartIndex);

                                    g.DrawString(draw, font, brush_text, pt);

                                    var s = g.MeasureString(draw, font, 2000, StringFormat.GenericTypographic);

                                    pt.X += s.Width;

                                    g.DrawString(dic.Value, font, brush_highLightText, pt);

                                    s = g.MeasureString(dic.Value, font, 2000, StringFormat.GenericTypographic);

                                    pt.X += s.Width + 0.2f;

                                    StartIndex = dic.Key + dic.Value.Length;
                                }

                                //if (StartIndex > str.Length)
                                //    break;
                            }

                            if (StartIndex < str.Length)
                            {
                                string draw = str.Substring(StartIndex, str.Length - StartIndex);

                                g.DrawString(draw, font, brush_text, pt);
                            }
                        }
                    }
                }
                else
                {
                    base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
                }
            }
            else
            {
                base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
            }
        }


        #endregion


        /// <summary>
        /// 截取出中括号内的文本
        /// </summary>
        /// <param name="calc">计算式</param>
        public Dictionary<int, string> GetFormatValue(string calc)
        {
            Dictionary<int, string> matchkeys = new Dictionary<int, string>();
            int leftIndex = 0;
            int rightIndex = 0;
            int leftCheckIndex = 0;
            int startIndex = 0;

            while (true)
            {
                //匹配正括号
                leftIndex = calc.IndexOf('[', startIndex);

                if (leftIndex > -1)
                {
                    if (leftIndex == calc.Length)
                        break;
                    //匹配反括号
                    rightIndex = calc.IndexOf("]", leftIndex + 1);

                    if (rightIndex > -1)
                    {
                        leftCheckIndex = calc.IndexOf("[", leftIndex + 1);

                        if (leftCheckIndex > -1)
                        {
                            //下一个正括号在当前反括号右边   当前正反括号为一个合格的表达式
                            if (leftCheckIndex < rightIndex && leftCheckIndex > leftIndex)
                            {
                                while (true)
                                {
                                    if (rightIndex == calc.Length)
                                        break;

                                    int _rightCheckIndex = calc.IndexOf(']', rightIndex + 1);

                                    if (_rightCheckIndex > -1)
                                    {

                                        int _leftCheckIndex = calc.IndexOf('[', leftCheckIndex + 1);
                                        if (_leftCheckIndex > -1)
                                        {
                                            if (_leftCheckIndex > leftCheckIndex && _leftCheckIndex < _rightCheckIndex)
                                            {
                                                rightIndex = _rightCheckIndex;
                                                leftCheckIndex = _leftCheckIndex;
                                            }
                                            else
                                            {
                                                rightIndex = _rightCheckIndex;
                                                break;
                                            }
                                        }
                                        else
                                        {
                                            rightIndex = _rightCheckIndex;
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        break;
                    }

                    if (rightIndex > -1)
                    {
                        string value = calc.Substring(leftIndex, rightIndex - leftIndex + 1);

                        matchkeys.Add(leftIndex, value);

                        startIndex = rightIndex;
                    }
                    else
                        startIndex = leftIndex;
                }
                else
                {
                    break;
                }
            }
            return matchkeys;
        }
    }
}
